package com.sunlands.zlcx.usercenter.service.task;

import com.sunlands.zlcx.usercenter.common.annotation.AutoLog;
import com.sunlands.zlcx.usercenter.constant.YN;
import com.sunlands.zlcx.usercenter.domain.VipUserDO;
import com.sunlands.zlcx.usercenter.exception.BusinessException;
import com.sunlands.zlcx.usercenter.exception.SendExceptionUtil;
import com.sunlands.zlcx.usercenter.service.UsersServiceImpl;
import com.sunlands.zlcx.usercenter.service.VipUserServiceImpl;
import com.sunlands.zlcx.usercenter.util.SimpleLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.sunlands.zlcx.usercenter.config.RedisConfig.CacheKeys.*;

@Service
@Slf4j
public class TaskVipServiceImpl {

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private VipUserServiceImpl vipUserService;
    @Autowired
    private SimpleLockUtil simpleLockUtil;
    @Autowired
    private SendExceptionUtil sendExceptionUtil;
    @Autowired
    private UsersServiceImpl usersService;
    @Value("${eureka.debug:false}")
    private Boolean debug;

    /**
     * vip过期后，结束vip身份
     */
    @AutoLog
    @Scheduled(cron = "${scheduled.endVip}")
    public void endVip() {
        if (debug || sendExceptionUtil.getSysdev().toLowerCase().equals("pre")) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getEndVipLock()) {
            return;
        }
        log.info("vip用户到期关闭，定时任务开始");
        int i = 0;
        Page<VipUserDO> page = null;
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("开始");
            while (i == 0 || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                i++;
                page = vipUserService.findAllExpireVip(pageable);
                List<VipUserDO> vipUserDOS = page.getContent();
                vipUserDOS.forEach(vipUserDO -> {
                    vipUserService.endVip(vipUserDO.getId());
                });
                Thread.sleep(100);
            }

            log.info("1、定时检查VIP是否已经到期，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}", page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
            i = 0;
            while (i == 0 || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                i++;
                page = vipUserService.findAllExpireHourTimesVip(pageable);
                List<VipUserDO> vipUserDOS = page.getContent();
                vipUserDOS.forEach(vipUserDO -> {
                    vipUserService.endVip(vipUserDO.getId());
                });
                Thread.sleep(100);
            }
            stopWatch.stop();
            log.info("2、定时检查VIP是否已经到期，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}", page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
        } catch (Exception e) {
            sendExceptionUtil.sendException("定时检查VIP是否已经到期 Exception: " + e.getMessage(), new BusinessException());
            log.error("定时检查VIP是否已经到期", e);
            log.error("", e);
        } finally {
            releaseEndVipLock();
        }
    }


    /**
     * 买多个月vip用于刷新vip的每月时长
     */
//    @AutoLog
    @Scheduled(cron = "${scheduled.user-vip-status}")
    public void refreshUserVipStatus() {
        if (debug) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getRefreshVipUserStatus()) {
            return;
        }
        log.info("vip定时更新用户表用户信息，定时任务开始");
        int i = 0;
        Page<VipUserDO> page = null;
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("开始");
            while (i == 0 || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                i++;
                page = vipUserService.page(pageable);
                List<VipUserDO> vipUserDOS = page.getContent();
                List<Long> userList = vipUserDOS.stream()
                        .filter(vip -> YN.YES.getCode() == Objects.requireNonNull(VipUserDO.LevelEnum.of(vip.getLevel())).vip)
                        .map(VipUserDO::getUserId)
                        .distinct()
                        .collect(Collectors.toList());
                usersService.updateVipStatus(userList, YN.YES.getCode());
                Thread.sleep(300);
            }

            //将所有过期的vip用户信息更新
            List<Long> allExpireUser = vipUserService.findAllExpireUser();
            if(!allExpireUser.isEmpty()){
                usersService.updateVipStatus(allExpireUser, YN.NO.getCode());
            }
            stopWatch.stop();
            log.info("定时刷新用户信息表vip状态，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}", page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
        } catch (Exception e) {
            sendExceptionUtil.sendException("定时刷新vip时长和到期时间，数据 Exception: " + e.getMessage(), new BusinessException());
            log.error("定时刷新用户信息表vip状态");
            log.error("", e);
        } finally {
            releaseRefreshVipUserStatus();
        }
    }

    /**
     * 买多个月vip用于刷新vip的每月时长
     */
    @AutoLog
    @Scheduled(cron = "${scheduled.refreshVip}")
    public void refreshVip() {
        if (debug || sendExceptionUtil.getSysdev().toLowerCase().equals("pre")) {
            log.warn("本地环境不启动定时");
            return;
        }

        if (!getRefreshVipLock()) {
            return;
        }
        log.info("vip用户到期刷新，定时任务开始");
        int i = 0;
        Page<VipUserDO> page = null;
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("开始");
            while (i == 0 || page.hasNext()) {
                Pageable pageable = new PageRequest(i, 100);
                i++;
                page = vipUserService.findAllRefreshVip(pageable);
                List<VipUserDO> vipUserDOS = page.getContent();
                vipUserDOS.forEach(vipUserDO -> vipUserService.refreshVip(vipUserDO.getId()));
                Thread.sleep(100);
            }
            stopWatch.stop();
            log.info("定时刷新vip时长和到期时间，本次处理数据条数 size = {} 总条数 = {} 耗时 = {}", page.getContent().size(), page.getTotalElements(), stopWatch.getTotalTimeMillis());
        } catch (Exception e) {
            sendExceptionUtil.sendException("定时刷新vip时长和到期时间，数据 Exception: " + e.getMessage(), new BusinessException());
            log.error("定时刷新vip时长和到期时间");
            log.error("", e);
        } finally {
            releaseRefreshVipLock();
        }
    }

    private boolean getEndVipLock() {
        String lockKey = VIP_USER_CONTROL_LOCK;

        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 1000 * 60);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releaseEndVipLock() {
        String lockKey = VIP_USER_CONTROL_LOCK;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseEndVipLock error", e);
        }
    }


    private boolean getRefreshVipLock() {
        String lockKey = VIP_USER_REFRESH_LOCK;

        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 1000 * 60);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releaseRefreshVipLock() {
        String lockKey = VIP_USER_REFRESH_LOCK;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseRefreshVipLock error", e);
        }
    }


    private boolean getRefreshVipUserStatus() {
        String lockKey = VIP_USER_VIP_STATUS_LOCK;

        try {
            return simpleLockUtil.acquireLock(lockKey, this.getClass().getName(), 1000 * 60);
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    private void releaseRefreshVipUserStatus() {
        String lockKey = VIP_USER_VIP_STATUS_LOCK;
        try {
            simpleLockUtil.releaseLock(lockKey, this.getClass().getName());
        } catch (Exception e) {
            log.error("releaseRefreshVipLock error", e);
        }
    }

}